﻿namespace CmeDataAdapter
{
    using CmeAdapter;
    using RS.CmeFastHandler;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;

    public class CmeDataServer
    {


        // Dictioanary
        //Dictionary<string, OpenFAST.Message> securityDic = new Dictionary<string, OpenFAST.Message>();
        Dictionary<string, SecurityDefinitionEntity> dictionary = new Dictionary<string, SecurityDefinitionEntity>();

        // futures
        EventWaitHandle eventTimer = new EventWaitHandle(false, EventResetMode.ManualReset);
        Tigera.CMEDAC.CME.cmeSD_FuturesDataTable futureTable = new Tigera.CMEDAC.CME.cmeSD_FuturesDataTable();
        DataHandle handle; // CME Handel
        Tigera.CMEDAC.CME.cmeSD_OptionsDataTable optionTable = new Tigera.CMEDAC.CME.cmeSD_OptionsDataTable();
        Dictionary<string, SnapShotEntity> snapshotDic = new Dictionary<string, SnapShotEntity>();



        #region Events

        public event System.EventHandler<RsErrorEventArgs> RS_ErrorReceived;

        public event System.EventHandler<RsInfoEventArgs> RS_InfoReceived;

        public event System.EventHandler<RsStatusEventArgs> RS_StatusChanged;

        public event System.EventHandler<SnapShotNewEventArgs> UpdatedDataReceived;

        #endregion Events

        #region Properties

        public string ChannelId
        {
            get;
            set;
        }

        public string ConnectionString
        {
            get;
            set;
        }

        public List<QuickFix42.MarketDataSnapshotFullRefresh> LatestQucikFixDictionary
        {
            get
            {
                SnapShotEntity[] entries;
                lock (snapshotDic)
                {
                    entries = new SnapShotEntity[snapshotDic.Count];
                    snapshotDic.Values.CopyTo(entries, 0);
                }
                List<QuickFix42.MarketDataSnapshotFullRefresh> fixlist = new List<QuickFix42.MarketDataSnapshotFullRefresh>();
                for (int i = 0; i < entries.Length; i++)
                {
                    QuickFix42.MarketDataSnapshotFullRefresh obj = ConvertoFixObject(entries[i]);
                    if (obj != null)
                    {
                        if (obj.ToString().IndexOf("269=") != -1)
                        {
                            fixlist.Add(obj);
                        }
                    }
                }
                return fixlist;
            }
        }

        #endregion Properties



        //  将Openfast 转换成 SnapshotEntity
        public void Convert2Entity(object data)
        {
            try
            {
                lock (this)
                {
                    Param p = (Param)data;
                    string key = p.key;
                    OpenFAST.Message msg = p.msg;
                    SnapShotEntity snapshotEntity = new SnapShotEntity();
                    snapshotEntity.SecurityId = key;        // SecurityId
                    if (dictionary.ContainsKey(key))       // SecurityDesc
                    {
                        snapshotEntity.SecurityDesc = dictionary[key].SecurityDesc;
                    }

                    snapshotEntity.SendingTime = msg.GetValue("SendingTime").ToString();

                    List<SnapShotLevel> bid = new List<SnapShotLevel>();
                    List<SnapShotLevel> offer = new List<SnapShotLevel>();
                    OpenFAST.SequenceValue entries = msg.GetSequence("MDEntries");
                    if (entries != null)
                    {
                        for (int i = 0; i < entries.Length; i++)
                        {
                            // MDEntryType 0:  1: 7: 8: 0:
                            string entryType = entries[i].GetValue("MDEntryType").ToString();
                            // Entry Price
                            string entryPx = entries[i].GetValue("MDEntryPx").ToString();
                            object quoteCondition = entries[i].GetValue("QuoteCondition");

                            #region Switch

                            switch (entryType)
                            {
                                case "0":
                                    //Bid
                                    if (quoteCondition == null)
                                    {
                                        SnapShotLevel bidLevel = new SnapShotLevel();
                                        bidLevel.Price = entryPx;
                                        bidLevel.Quantity = entries[i].GetValue("MDEntrySize").ToString();
                                        if (entries[i].GetValue("NumberOfOrders") != null)
                                        {
                                            bidLevel.NumberOfOrders = entries[i].GetValue("NumberOfOrders").ToString();
                                        }
                                        bid.Add(bidLevel);
                                    }
                                    break;
                                case "1":
                                    //Offer
                                    if (quoteCondition == null)
                                    {
                                        SnapShotLevel offerLevel = new SnapShotLevel();
                                        offerLevel.Price = entryPx;
                                        offerLevel.Quantity = entries[i].GetValue("MDEntrySize").ToString();
                                        if (entries[i].GetValue("NumberOfOrders") != null)
                                        {
                                            offerLevel.NumberOfOrders = entries[i].GetValue("NumberOfOrders").ToString();
                                        }
                                        offer.Add(offerLevel);
                                    }
                                    break;
                                case "2":
                                    //Trade
                                    snapshotEntity.TradePrice = entryPx;
                                    if (entries[i].GetValue("MDEntrySize") != null)
                                    {
                                        snapshotEntity.TradeSize = entries[i].GetValue("MDEntrySize").ToString();
                                    }
                                    if (entries[i].GetValue("TradeVolume") != null)
                                    {
                                        snapshotEntity.TotalVolumeTraded = entries[i].GetValue("TradeVolume").ToString();
                                    }
                                    break;
                                case "4":   //opening price
                                    snapshotEntity.OpeningPrice = entryPx;
                                    continue;
                                case "6":   //settlement price
                                    snapshotEntity.SettlementPrice = entryPx;
                                    continue;
                                case "7":
                                    // Trading Session High Price
                                    snapshotEntity.HighPrice = entryPx;
                                    break;
                                case "8":
                                    // Trading Sessiion Low Price
                                    snapshotEntity.LowPrice = entryPx;
                                    break;
                                case "N":
                                    // Session High Bid
                                    snapshotEntity.HighBid = entryPx;
                                    break;
                                case "O":
                                    // Session Low offer
                                    snapshotEntity.LowOffer = entryPx;
                                    break;
                                default:
                                    break;
                            }

                            #endregion
                        }
                    }
                    snapshotEntity.Bid = bid;
                    snapshotEntity.Offer = offer;
                    lock (snapshotDic)
                    {
                        snapshotDic[key] = snapshotEntity;
                    }
                }
            }
            catch (Exception ex)
            {
                RsErrorEventArgs args = new RsErrorEventArgs();
                args.Message += "StackTrace:" + ex.StackTrace;
                args.Message += "\r\nMessage:" + ex.Message;
                args.Message += "\r\nInnerException:" + ex.InnerException;
                if (this.RS_ErrorReceived != null)
                {
                    this.RS_ErrorReceived(this, args);
                }
            }
        }

        public SnapShotEntity Convert2SnapShotEntity(OpenFAST.Message msg, string tradePrice, string tradeSize)
        {
            string key = msg.GetValue("SecurityID").ToString();
            SnapShotEntity snapshotEntity = new SnapShotEntity();
            snapshotEntity.SecurityId = key;        // SecurityId
            if (dictionary.ContainsKey(key))       // SecurityDesc
            {
                snapshotEntity.SecurityDesc = dictionary[key].SecurityDesc;
            }
            snapshotEntity.SendingTime = msg.GetValue("SendingTime").ToString();

            List<SnapShotLevel> bid = new List<SnapShotLevel>();
            List<SnapShotLevel> offer = new List<SnapShotLevel>();
            OpenFAST.SequenceValue entries = msg.GetSequence("MDEntries");
            if (entries != null)
            {
                for (int i = 0; i < entries.Length; i++)
                {
                    // MDEntryType 0:  1: 7: 8: 0:
                    string entryType = entries[i].GetValue("MDEntryType").ToString();
                    // Entry Price
                    string entryPx = entries[i].GetValue("MDEntryPx").ToString();
                    object quoteCondition = entries[i].GetValue("QuoteCondition");

                    #region Switch

                    switch (entryType)
                    {
                        case "0":
                            //Bid
                            if (quoteCondition == null)
                            {
                                SnapShotLevel bidLevel = new SnapShotLevel();
                                bidLevel.Price = entryPx;
                                bidLevel.Quantity = entries[i].GetValue("MDEntrySize").ToString();
                                if (entries[i].GetValue("NumberOfOrders") != null)
                                {
                                    bidLevel.NumberOfOrders = entries[i].GetValue("NumberOfOrders").ToString();
                                }
                                bid.Add(bidLevel);
                            }
                            break;
                        case "1":
                            //Offer
                            if (quoteCondition == null)
                            {
                                SnapShotLevel offerLevel = new SnapShotLevel();
                                offerLevel.Price = entryPx;
                                offerLevel.Quantity = entries[i].GetValue("MDEntrySize").ToString();
                                if (entries[i].GetValue("NumberOfOrders") != null)
                                {
                                    offerLevel.NumberOfOrders = entries[i].GetValue("NumberOfOrders").ToString();
                                }
                                offer.Add(offerLevel);
                            }
                            break;
                        case "2":
                            //Trade
                            if (tradePrice != string.Empty)
                                snapshotEntity.TradePrice = tradePrice;
                            else
                                snapshotEntity.TradePrice = entryPx;
                            if (tradeSize != string.Empty)
                                snapshotEntity.TradeSize = tradeSize;
                            else
                            {
                                if (entries[i].GetValue("TradeVolume") == null || entries[i].GetValue("TradeVolume").ToString().Equals("0"))
                                {
                                    snapshotEntity.TradeSize = "0";
                                }
                                else
                                {
                                    snapshotEntity.TradeSize = "1";
                                }
                            }
                            if (entries[i].GetValue("TradeVolume") != null)
                            {
                                snapshotEntity.TotalVolumeTraded = entries[i].GetValue("TradeVolume").ToString();
                            }
                            break;
                        case "4":   //opening price
                            snapshotEntity.OpeningPrice = entryPx;
                            continue;
                        case "6":   //settlement price
                            snapshotEntity.SettlementPrice = entryPx;
                            continue;
                        case "7":
                            // Trading Session High Price
                            snapshotEntity.HighPrice = entryPx;
                            break;
                        case "8":
                            // Trading Sessiion Low Price
                            snapshotEntity.LowPrice = entryPx;
                            break;
                        case "N":
                            // Session High Bid
                            snapshotEntity.HighBid = entryPx;
                            break;
                        case "O":
                            // Session Low offer
                            snapshotEntity.LowOffer = entryPx;
                            break;
                        default:
                            break;
                    }

                    #endregion
                }
            }
            snapshotEntity.Bid = bid;
            snapshotEntity.Offer = offer;
            return snapshotEntity;
        }

        // 将 DataTable 转换成 Security Definition Dictionary
        public void Convet2SecurityEntity()
        {
            if (optionTable.Rows.Count > 0)
            {
                // Options
                for (int i = 0; i < optionTable.Rows.Count; i++)
                {
                    Tigera.CMEDAC.CME.cmeSD_OptionsRow row = (Tigera.CMEDAC.CME.cmeSD_OptionsRow)optionTable.Rows[i];
                    SecurityDefinitionEntity entity = new SecurityDefinitionEntity();
                    entity.SecurityId = row.SecurityID;
                    entity.SecurityDesc = row.SecurityDesc;
                    entity.SecurityGroup = row.SecurityGroup;
                    entity.SecurityExchange = row.SecurityExchange;
                    entity.CFICode = row.CFICode;
                    entity.StrikePrice = row.StrikePrice;
                    entity.MaturityMonthYear = row.MaturityMonthYear;
                    dictionary[row.SecurityID] = entity;
                }
            }
            else
            {
                // Futures
                for (int i = 0; i < futureTable.Rows.Count; i++)
                {
                    Tigera.CMEDAC.CME.cmeSD_FuturesRow row = (Tigera.CMEDAC.CME.cmeSD_FuturesRow)futureTable.Rows[i];
                    SecurityDefinitionEntity entity = new SecurityDefinitionEntity();
                    entity.SecurityId = row.SecurityID;
                    entity.SecurityDesc = row.SecurityDesc;
                    entity.SecurityGroup = row.SecurityGroup;
                    entity.SecurityExchange = row.SecurityExchange;
                    entity.CFICode = row.CFICode;
                    entity.StrikePrice = row.StrikePrice;
                    entity.MaturityMonthYear = row.MaturityMonthYear;
                    dictionary[row.SecurityID] = entity;
                }
            }
        }

        /// <summary>
        ///  Start to listen
        /// </summary>
        public void Start()
        {
            if (string.IsNullOrEmpty(ConnectionString))
            {
                RsErrorEventArgs args = new RsErrorEventArgs();
                args.Message = "Please set database connection string";
                if (this.RS_ErrorReceived != null)
                {
                    this.RS_ErrorReceived(this, args);
                }
                return;
            }
            DAC.ConnectionSetting.SetConnecionString(this.ConnectionString);
            // 先从数据库中下载协议
            LoadSecurityDefinition();
            // 根据配置文件初始化环境信息
            handle = new DataHandle();
            handle.ChannelId = ChannelId;
            // Subcrible all message
            // Sanpshot
            handle.RS_SnapShotDataReceived += new EventHandler<RsSnapshotEventArgs>(handle_RS_SnapShotDataReceived);
            // Increment data
            handle.RS_IncrementDataReceived += new EventHandler<RsIncrementEventArgs>(handle_RS_IncrementDataReceived);
            // Information
            handle.RS_InfoReceived += new EventHandler<RsInfoEventArgs>(handle_RS_InfoReceived);
            // Error message
            handle.RS_ErrorReceived += new EventHandler<RsErrorEventArgs>(handle_RS_ErrorReceived);
            // Status message
            handle.RS_StatusChanged += new EventHandler<RsStatusEventArgs>(handle_RS_StatusChanged);
            // Start to listen.
            handle.Start();
        }

        /// <summary>
        /// Stop listen
        /// </summary>
        public void Stop()
        {
            handle.Stop();
            eventTimer.Reset();
        }

        private QuickFix42.MarketDataSnapshotFullRefresh ConvertoFixObject(SnapShotEntity entity)
        {
            try
            {
                lock (snapshotDic)
                {
                    // Fix message
                    QuickFix42.MarketDataSnapshotFullRefresh snapshot = new QuickFix42.MarketDataSnapshotFullRefresh();
                    snapshot.setField(56, "TigEra");// TT 默認值
                    snapshot.setField(48, entity.SecurityId);//SecurityID
                    if (entity.SecurityDesc != null)
                    {
                        snapshot.setField(107, entity.SecurityDesc);//SecurityDesc
                    }
                    else
                    {
                        snapshot.setField(107, "");//SecurityDesc
                    }
                    // Symbol
                    // 如果不存在SecurityID 则推出
                    if (dictionary.ContainsKey(entity.SecurityId) == false)
                    {
                        return null;
                    }
                    SecurityDefinitionEntity securityMsg = dictionary[entity.SecurityId];
                    //string symbol = securityMsg.GetValue("Symbol").ToString();
                    string symbol = securityMsg.SecurityGroup;

                    snapshot.setField(55, symbol);            // Symbol
                    //167=FUT 证券类型（包括期货FUT，期权OPT，股票等） 来至 CFICODE
                    string cifcode = securityMsg.CFICode;
                    if (cifcode.Substring(0, 1) == "F")
                    {
                        snapshot.setField(167, "FUT");
                    }
                    else
                    {
                        snapshot.setField(167, "OPT");
                        // 201 put call
                        if (cifcode.Substring(1, 1) == "C")
                        {
                            snapshot.setField(201, "1"); // Call
                        }
                        else
                        {
                            snapshot.setField(201, "0"); // Put
                        }
                        // 202 StrikePrice
                        if (securityMsg.StrikePrice != "")
                        {
                            snapshot.setField(202, securityMsg.StrikePrice);
                        }
                    }

                    snapshot.setField(200, securityMsg.MaturityMonthYear);   // MaturityMonthYear
                    snapshot.setField(207, securityMsg.SecurityExchange);    // SecurityExchange
                    //snapshot.setField(207, "CME");    // SecurityExchange
                    snapshot.setField(262, "");// 不设置值
                    //NoMDEntries 268
                    //string str268 = Utils.GetNOEntries(entity);
                    //snapshot.setField(268, str268);
                    // 0=Bid

                    decimal lastprice;

                    if (entity.TradePrice != "")
                        lastprice = System.Convert.ToDecimal(entity.TradePrice);
                    else
                        lastprice = 0;

                    int iLevel = 0;

                    for (int i = 0; i < entity.Bid.Count; i++)
                    {
                        string bidPrice = entity.Bid[i].Price;
                        if (bidPrice != "" && lastprice >= System.Convert.ToDecimal(bidPrice))
                        {
                            iLevel += 1;

                            QuickFix.Group group = new QuickFix.Group(268, 269, new int[] { 269, 290, 270, 271 });
                            group.setField(269, "0");
                            // group.setField(290, (i + 1).ToString()); // lavel
                            group.setField(290, (iLevel).ToString()); // lavel
                            group.setField(270, bidPrice);                      // price
                            group.setField(271, entity.Bid[i].Quantity);// size
                            snapshot.addGroup(group);
                        }
                    }
                    // 1=Offer

                    iLevel = 0;

                    for (int i = 0; i < entity.Offer.Count; i++)
                    {
                        string offerPrice = entity.Offer[i].Price;
                        if (offerPrice != "" && lastprice <= System.Convert.ToDecimal(offerPrice))
                        {
                            iLevel += 1;
                            QuickFix.Group group = new QuickFix.Group(268, 269, new int[] { 269, 290, 270, 271 });
                            group.setField(269, "1");
                            //group.setField(290, (i + 1).ToString());// lavel
                            group.setField(290, (iLevel).ToString());// lavel
                            group.setField(270, offerPrice);                      // price
                            group.setField(271, entity.Offer[i].Quantity);// size
                            snapshot.addGroup(group);
                        }
                    }
                    // 2 = Trade
                    if (entity.TradePrice != "")
                    {
                        QuickFix.Group group = new QuickFix.Group(268, 269, new int[] { 269, 270, 271 });
                        group.setField(269, "2");
                        group.setField(270, entity.TradePrice);             // price
                        if (!string.IsNullOrEmpty(entity.TradeSize))
                        {
                            group.setField(271, entity.TradeSize);              // size 从CME 那里获取的总是空
                        }
                        snapshot.addGroup(group);
                    }
                    // 4 = opening price
                    if (entity.OpeningPrice != "")
                    {
                        QuickFix.Group group = new QuickFix.Group(268, 269, new int[] { 269, 270 });
                        group.setField(269, "4");
                        group.setField(270, entity.OpeningPrice);             // price
                        snapshot.addGroup(group);
                    }
                    if (entity.SettlementPrice != "")
                    {
                        QuickFix.Group group = new QuickFix.Group(268, 269, new int[] { 269, 270 });
                        group.setField(269, "6");
                        group.setField(270, entity.SettlementPrice);             // price
                        snapshot.addGroup(group);
                    }
                    // 7 = Trading Session High price
                    if (entity.HighPrice != "")
                    {
                        QuickFix.Group group = new QuickFix.Group(268, 269, new int[] { 269, 270 });
                        group.setField(269, "7");
                        group.setField(270, entity.HighPrice);             // price
                        snapshot.addGroup(group);
                    }
                    // 8 = Trading Session Low Price
                    if (entity.LowPrice != "")
                    {
                        QuickFix.Group group = new QuickFix.Group(268, 269, new int[] { 269, 270 });
                        group.setField(269, "8");
                        group.setField(270, entity.LowPrice);             // price
                        snapshot.addGroup(group);
                    }
                    // N = Session High Bid
                    // O = Session Low Offer
                    snapshot.setField(34, ""); // MsgSeqNum 不设置值
                    snapshot.setField(49, "TigEra");// CONSTANT  默認值
                    //snapshot.setField(52, DateTime.Now.ToString("yyyyMMdd-hh:mm:ss.fff"));// SendingTime

                    snapshot.setField(52, entity.SendingTime.ToString());

                    if (entity.TotalVolumeTraded != "")
                    {
                        snapshot.setField(387, entity.TotalVolumeTraded);   //  TotalVolumeTraded
                    }
                    return snapshot;
                }
            }
            catch (Exception ex)
            {
                RsErrorEventArgs args = new RsErrorEventArgs();
                args.Message += "StackTrace:" + ex.StackTrace;
                args.Message += "\r\nMessage:" + ex.Message;
                args.Message += "\r\nInnerException:" + ex.InnerException;
                if (this.RS_ErrorReceived != null)
                {
                    this.RS_ErrorReceived(this, args);
                }
                return null;
            }
        }

        private void DeleteBidOrOffer(SnapShotEntity entry, string entryType, string entryPrice)
        {
            lock (snapshotDic)
            {
                switch (entryType)
                {
                    case "0":
                        // Bid ：
                        for (int i = 0; i < entry.Bid.Count; i++)
                        {
                            // 如相等 则删除
                            if (Decimal.Parse(entry.Bid[i].Price) == Decimal.Parse(entryPrice))
                            {
                                entry.Bid.RemoveAt(i);
                                break;
                            }
                        }
                        break;
                    case "1":
                        //Offer     Offer 的数据规律是从小到大
                        for (int i = 0; i < entry.Offer.Count; i++)
                        {
                            if (decimal.Parse(entry.Offer[i].Price) == decimal.Parse(entryPrice))
                            {
                                entry.Offer.RemoveAt(i);
                                break;
                            }
                        }
                        break;
                    default:
                        break;
                }
            }
        }

        // Receive Error Message
        void handle_RS_ErrorReceived(object sender, RsErrorEventArgs e)
        {
            if (this.RS_ErrorReceived != null)
            {
                this.RS_ErrorReceived(this, e);
            }
        }

        // Receive increment data
        void handle_RS_IncrementDataReceived(object sender, RsIncrementEventArgs e)
        {
            SendIncrementSecurityDefinition(e.Message, e.TradePrice, e.TradeSize);
        }

        // Rceive information
        void handle_RS_InfoReceived(object sender, RsInfoEventArgs e)
        {
            if (this.RS_InfoReceived != null)
            {
                this.RS_InfoReceived(this, e);
            }
        }

        // Receive snapshot data
        void handle_RS_SnapShotDataReceived(object sender, RsSnapshotEventArgs e)
        {
            try
            {
                // 因为带参数，所以用一下方式调用线程。
                WaitCallback callback = new WaitCallback(this.Convert2Entity);
                Param p = new Param() { key = e.Key, msg = e.Message };
                ThreadPool.QueueUserWorkItem(callback, p);
            }
            catch (Exception ex)
            {
                RsErrorEventArgs args = new RsErrorEventArgs();
                args.Message += "StackTrace:" + ex.StackTrace;
                args.Message += "\r\nMessage:" + ex.Message;
                args.Message += "\r\nInnerException:" + ex.InnerException;
                if (this.RS_ErrorReceived != null)
                {
                    this.RS_ErrorReceived(this, args);
                }
            }
        }

        // Receive status change message
        void handle_RS_StatusChanged(object sender, RsStatusEventArgs e)
        {
            if (this.RS_StatusChanged != null)
            {
                this.RS_StatusChanged(this, e);
            }
        }

        /// <summary>
        /// 是否订阅
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        private bool IsBook(SnapShotEntity entity)
        {
            bool isBook = false;
            for (int i = 0; i < entity.Bid.Count; i++)
            {
                string bidPrice = entity.Bid[i].Price;
                if (bidPrice != "")
                {
                    isBook = true;
                }
            }
            // 1=Offer
            for (int i = 0; i < entity.Offer.Count; i++)
            {
                string offerPrice = entity.Offer[i].Price;
                if (offerPrice != "")
                {
                    isBook = true;
                }
            }
            // 2 = Trade
            if (entity.TradePrice != "" || entity.OpeningPrice != "" || entity.SettlementPrice != "" || entity.HighPrice != "" || entity.LowPrice != "")
            {
                isBook = true;
            }
            return isBook;
        }

        private void LoadSecurityDefinition()
        {
            // Clear security definition dictionary
            dictionary.Clear();
            optionTable.Rows.Clear();
            futureTable.Rows.Clear();
            // Get data from database
            cmeSD_FuturesTableAdapter futureAdapter = new cmeSD_FuturesTableAdapter();
            cmeSD_OptionsTableAdapter optionAdapter = new cmeSD_OptionsTableAdapter();
            // options
            optionAdapter.FillBy(optionTable, ChannelId);
            // futures
            futureAdapter.FillBy(futureTable, ChannelId);

            // 将 DataTable 转换成 Dictionary
            Convet2SecurityEntity();
            RsInfoEventArgs args = new RsInfoEventArgs();
            args.ChannelId = ChannelId;
            args.Message = " Security Definition count is: " + dictionary.Count.ToString();
            if (RS_InfoReceived != null)
            {
                this.RS_InfoReceived(this, args);
            }
        }

        private void OverlayBidOrOffer(SnapShotEntity entry, string entryType, string priceLevel,
            string entryPrice, string entrySize, string numberOfOrders)
        {
            if (entrySize != "")
            {
                // 更新
                UpdateBidOrOffer(entry, entryType, priceLevel, entryPrice, entrySize, numberOfOrders);
            }
            else
            {
                // 删除
                DeleteBidOrOffer(entry, entryType, entryPrice);
            }
        }

        private void SendIncrementSecurityDefinition(OpenFAST.Message msg, string tradePrice, string tradeSize)
        {
            SnapShotNewEventArgs args = new SnapShotNewEventArgs();
            SnapShotEntity ssEntity = Convert2SnapShotEntity(msg, tradePrice, tradeSize);
            if (ssEntity != null)
            {
                if (dictionary.ContainsKey(ssEntity.SecurityId))
                {
                    SecurityDefinitionEntity sdEntity = dictionary[ssEntity.SecurityId];
                    MarketData data = new MarketData();
                    data.SsEntity = ssEntity;
                    data.SdEntity = sdEntity;
                    args.ChannelID = ChannelId;
                    args.Data = data;
                    // 只发送有值的 Book
                    if (IsBook(ssEntity))
                    {
                        if (this.UpdatedDataReceived != null)
                        {
                            this.UpdatedDataReceived(this, args);
                        }
                    }
                }
            }
        }

        private void UpdateBidOrOffer(SnapShotEntity entry, string entryType, string priceLevel,
            string entryPrice, string entrySize, string numberOfOrders)
        {
            lock (snapshotDic)
            {
                bool operated = false; //是否已处理
                switch (entryType)
                {
                    case "0":
                        // Bid ：  Bid 数据规律是从大到小
                        // 有则更新，无则创建
                        for (int i = 0; i < entry.Bid.Count; i++)
                        {
                            // 有则更新
                            if (Decimal.Parse(entry.Bid[i].Price) == Decimal.Parse(entryPrice))
                            {
                                //  当前值于更新值相等的时候更新现有数据
                                entry.Bid[i].Quantity = entrySize;
                                entry.Bid[i].NumberOfOrders = numberOfOrders;
                                operated = true;
                                break;
                            }
                            else if (Decimal.Parse(entry.Bid[i].Price) < Decimal.Parse(entryPrice))
                            {
                                // 如果当前值小于新值则在当前位置插入新值
                                SnapShotLevel bidLevel = new SnapShotLevel();
                                bidLevel.Price = entryPrice;
                                bidLevel.Quantity = entrySize;
                                bidLevel.NumberOfOrders = numberOfOrders;
                                entry.Bid.Insert(i, bidLevel);
                                operated = true;
                                break;
                            }
                            else
                            {
                                // 当前值大于更新值时循环下一次
                            }
                        }
                        // 当在for 循环里面没有处理此值则在最后添加
                        if (operated == false && entry.Bid.Count < 10)
                        {
                            // 在最后添加更新值

                            SnapShotLevel bidLevel = new SnapShotLevel();
                            bidLevel.Price = entryPrice;
                            bidLevel.Quantity = entrySize;
                            bidLevel.NumberOfOrders = numberOfOrders;
                            entry.Bid.Add(bidLevel);

                        }
                        // List 超过10 个则删除多余部分
                        if (entry.Bid.Count > 10)
                        {
                            entry.Bid.RemoveAt(10);
                        }
                        break;
                    case "1":
                        //Offer     Offer 的数据规律是从小到大
                        // 有则更新， 无则创建
                        for (int i = 0; i < entry.Offer.Count; i++)
                        {
                            if (decimal.Parse(entry.Offer[i].Price) == decimal.Parse(entryPrice))
                            {
                                entry.Offer[i].Quantity = entrySize;
                                entry.Offer[i].NumberOfOrders = numberOfOrders;
                                operated = true;
                                break;
                            }
                            else if (decimal.Parse(entry.Offer[i].Price) > decimal.Parse(entryPrice))
                            {
                                SnapShotLevel bidLevel = new SnapShotLevel();
                                bidLevel.Price = entryPrice;
                                bidLevel.Quantity = entrySize;
                                bidLevel.NumberOfOrders = numberOfOrders;
                                entry.Offer.Insert(i, bidLevel);
                                operated = true;
                                break;
                            }
                            else
                            {
                                // 当前值大于更新值时循环下一次
                            }
                        }
                        // 当在for 循环里面没有处理此值则在最后添加
                        // 当在for 循环里面没有处理此值则在最后添加
                        if (operated == false && entry.Offer.Count < 10)
                        {
                            // 在最后添加更新值
                            SnapShotLevel bidLevel = new SnapShotLevel();
                            bidLevel.Price = entryPrice;
                            bidLevel.Quantity = entrySize;
                            bidLevel.NumberOfOrders = numberOfOrders;
                            entry.Offer.Add(bidLevel);
                        }
                        // List 超过10 个则删除多余部分
                        if (entry.Offer.Count > 10)
                        {
                            entry.Offer.RemoveAt(10);
                        }
                        break;
                    default:
                        break;
                }
            }
        }

        private void UpdateSanpshotDic(OpenFAST.Message msg)
        {
            try
            {
                if (msg.Template.Name.IndexOf("MDSecurityStatus") != -1)
                {
                    return;
                }
                OpenFAST.SequenceValue entries = msg.GetSequence("MDEntries");
                for (int i = 0; i < entries.Length; i++)
                {
                    string securityID;
                    SnapShotEntity entry = new SnapShotEntity();
                    lock (snapshotDic)
                    {
                        // 279 =  MDUpdateAction
                        string updateAction = entries[i].GetValue("MDUpdateAction").ToString(); // 0:new 1:change 2:delete 5:overlay
                        // 48 =   SecurityID
                        securityID = entries[i].GetValue("SecurityID").ToString();
                        // 269 =  Entry Type
                        string entryType = entries[i].GetValue("MDEntryType").ToString(); // 0:bid 1:offer 7:8:O:N.....
                        // 排除 Quoteconditon 有值的数据
                        if (entries.Sequence.Group.HasField("QuoteCondition") == true)
                        {
                            object quotecondion = entries[i].GetValue("QuoteCondition");
                            if (quotecondion != null)
                            {
                                continue;
                            }
                        }
                        // Find the snapshot entry
                        // The increment data values
                        string priceLevel = "", entryPrice = "", entrySize = "", numberOfOrders = "", totalVolumnTrade = "";
                        if (this.snapshotDic.ContainsKey(securityID))
                        {
                            entry = snapshotDic[securityID];
                            // 270 =  Entry Price
                            if (entries[i].GetValue("MDEntryPx") != null)
                            {
                                entryPrice = entries[i].GetValue("MDEntryPx").ToString();
                            }
                            else
                            {
                                // 此掉数据不处理
                                continue;
                            }
                            #region switch
                            switch (entryType)
                            {
                                case "0":
                                case "1":
                                    // 1023 = Price Level
                                    if (entries[i].GetValue("MDPriceLevel") == null)
                                    {
                                        priceLevel = ((OpenFAST.Template.Scalar)(entries.Sequence.Group.Fields[1])).DefaultValue.ToString();
                                    }
                                    else
                                    {
                                        priceLevel = entries[i].GetValue("MDPriceLevel").ToString();
                                    }
                                    // 346 =  NumberOfOrders   *** 模板36 没有 NumberOfOrders field
                                    if (entries.Sequence.Group.HasField("NumberOfOrders") == true)
                                    {
                                        numberOfOrders = entries[i].GetValue("NumberOfOrders").ToString();
                                    }
                                    // 271 =  Entry Size
                                    if (entries[i].GetValue("MDEntrySize") != null)
                                    {
                                        entrySize = entries[i].GetValue("MDEntrySize").ToString();
                                    }
                                    break;
                                case "2":       // Trading Session High Price
                                    if (entries[i].GetValue("TradeVolume") != null)
                                    {
                                        totalVolumnTrade = entries[i].GetValue("TradeVolume").ToString();
                                    }
                                    if (entries[i].GetValue("MDEntrySize") != null)
                                    {
                                        entrySize = entries[i].GetValue("MDEntrySize").ToString();
                                    }
                                    // Set value
                                    entry.TradePrice = entryPrice;
                                    entry.TradeSize = entrySize;
                                    entry.TotalVolumeTraded = totalVolumnTrade;
                                    continue;
                                case "4":   //opening price
                                    entry.OpeningPrice = entryPrice;
                                    continue;
                                case "6":   //settlement price
                                    entry.SettlementPrice = entryPrice;
                                    continue;
                                case "7":        // Trading Session High Price
                                    entry.HighPrice = entryPrice;
                                    continue;
                                case "8":        // Trading Sessiion Low Price
                                    entry.LowPrice = entryPrice;
                                    continue;
                                case "O":        // Session Low offer
                                    entry.LowOffer = entryPrice;
                                    continue;
                                case "N":        // Session High Bid
                                    entry.HighBid = entryPrice;
                                    continue;
                                default:
                                    // 2: Trade
                                    //Utils.ErrorLog("Error = MDPriceLevel:" + msg.ToString());
                                    continue;

                            }
                            // 只有当 Increment 数据真对 Bid 或 Offer 的时候计算
                            switch (updateAction)
                            {
                                case "0":
                                    // New
                                    UpdateBidOrOffer(entry, entryType, priceLevel, entryPrice, entrySize, numberOfOrders);
                                    break;
                                case "1":
                                    // Change
                                    UpdateBidOrOffer(entry, entryType, priceLevel, entryPrice, entrySize, numberOfOrders);
                                    break;
                                case "2":
                                    // Delete
                                    DeleteBidOrOffer(entry, entryType, entryPrice);
                                    break;
                                case "5":
                                    // Overlay
                                    OverlayBidOrOffer(entry, entryType, priceLevel, entryPrice, entrySize, numberOfOrders);
                                    break;
                                default:
                                    break;
                            }

                            #endregion
                        }
                        else
                        {
                            cmeLostSecurityDataTableAdapter lostAdapter = new cmeLostSecurityDataTableAdapter();
                            lostAdapter.Insert(ChannelId, securityID);
                        }
                        //SendIncrementSecurityDefinition(securityID);
                    }

                }
            }
            catch (Exception ex)
            {
                RsErrorEventArgs args = new RsErrorEventArgs();
                args.Message += "StackTrace:" + ex.StackTrace;
                args.Message += "\r\nMessage:" + ex.Message;
                args.Message += "\r\nInnerException:" + ex.InnerException;
                args.Message += "\r\nFastMessage:" + msg.ToString();
                if (this.RS_ErrorReceived != null)
                {
                    this.RS_ErrorReceived(this, args);
                }
            }
        }


    }
}